package org.bing.tester;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;

import org.bing.engine.utility.codec.SimpleReflectHelper;

@SuppressWarnings({ "rawtypes" })
public class EqualsHelper {

    public static boolean deepEquals(Object o1, Object o2) {
        if (o1 == o2) {
            return true;
        }
        if (o1 == null || o2 == null) {
            return false;
        }
        if (!o1.getClass().getName().equals(o2.getClass().getName())) {
            return false;
        }
        if (o1.getClass() == List.class) {
            if (o2 != List.class) {
                return false;
            }
            return deepListEquals((List) o1, (List) o2);
        }
        // reflect requals
        SimpleReflectHelper helper = SimpleReflectHelper.instance(o1);
        Field[] fields = helper.getTotalFields();
        for (Field field : fields) {
            Object fo1 = helper.getValue(o1, field);
            Object fo2 = helper.getValue(o2, field);
            // primitive type
            if (field.getType().isPrimitive()) {
                if (!fo1.equals(fo2)) {
                    return false;
                }
            }
            // string and date type
            if (field.getType() == String.class || field.getType() == Date.class) {
                if (!fo1.equals(fo2)) {
                    return false;
                }
            }
            // list, iterator equal
            if (field.getType() == List.class) {
                List lst1 = (List) fo1;
                List lst2 = (List) fo2;
                if (!deepListEquals(lst1, lst2)) {
                    return false;
                }
            }
        }
        return true;
    }

    private static boolean deepListEquals(List lst1, List lst2) {
        if (lst1 == lst2) {
            return true;
        }
        if (lst1 == null || lst2 == null) {
            return false;
        }
        if (lst1.size() != lst2.size()) {
            return false;
        }
        for (int i = 0; i < lst1.size(); i++) {
            Object lo1 = lst1.get(i);
            Object lo2 = lst2.get(i);
            if (!deepEquals(lo1, lo2)) {
                return false;
            }
        }
        return true;
    }
}
